package com.linb.pan.server.modules.file.controller;

import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.linb.pan.core.constants.BPanConstants;
import com.linb.pan.core.response.R;
import com.linb.pan.core.utils.IdUtil;
import com.linb.pan.server.common.utils.UserIdUtil;
import com.linb.pan.server.modules.file.constants.FileConstants;
import com.linb.pan.server.modules.file.context.*;
import com.linb.pan.server.modules.file.converter.FileConverter;
import com.linb.pan.server.modules.file.entity.BPanUserFile;
import com.linb.pan.server.modules.file.enums.DelFlagEnum;
import com.linb.pan.server.modules.file.po.*;
import com.linb.pan.server.modules.file.service.IFileService;
import com.linb.pan.server.modules.file.service.IUserFileService;
import com.linb.pan.server.modules.file.vo.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@RestController
@Validated
@Api(tags = "文件相关接口")
public class FileController {

    @Autowired
    private IUserFileService userFileService;

    @Autowired
    private FileConverter fileConverter;

    @ApiOperation(value = "查看解密后的文件id")
    @GetMapping("decrypt_file")
    public R<List<DecryptFileVO>> getDecryptFile() {
        List<DecryptFileVO> list = Lists.newArrayList();
        List<BPanUserFile> records = userFileService.lambdaQuery().list();
        for (BPanUserFile record : records) {
            DecryptFileVO vo = new DecryptFileVO();
            vo.setFileId(record.getFileId());
            vo.setFilename(record.getFilename());
            list.add(vo);
        }
        return R.data(list);
    }

    @ApiOperation(value = "查询文件列表")
    @GetMapping("files")
    public R<List<BPanUserFileVO>> getFileList(@NotBlank(message = "父文件夹id不能为空") @RequestParam(value = "parentId", required = false) String parentId,
                                               @RequestParam(value = "fileTypes", required = false, defaultValue = FileConstants.ALL_FILE_TYPE) String fileTypes) {
        //解密
        Long realParentId = -1L;
        if (!Objects.equals(parentId, FileConstants.ALL_FILE_TYPE)) {
            realParentId = IdUtil.decrypt(parentId);
        }
        //将文件类型以__,__分割开来，转换成int后存放在fileTypeArray中
        //-1__,__2__,__3 可以变成 [-1, 2, 3]
        List<Integer> fileTypeArray = null;
        if (!fileTypes.equals(FileConstants.ALL_FILE_TYPE)) {
            fileTypeArray = Splitter.on(BPanConstants.COMMON_SEPARATOR).splitToList(fileTypes)
                    .stream().map(Integer::valueOf).collect(Collectors.toList());
        }
        QueryFileListContext context = new QueryFileListContext();
        context.setParentId(realParentId);
        context.setFileTypeArray(fileTypeArray);
        context.setUserId(UserIdUtil.get());
        context.setDelFlag(DelFlagEnum.NO.getCode());
        List<BPanUserFileVO> result = userFileService.getFileList(context);
        return R.data(result);
    }

    @PostMapping("file/folder")
    @ApiOperation(value = "创建文件夹")
    public R<String> createFolder(@Validated @RequestBody CreateFolderPO po) {
        CreateFolderContext context = fileConverter.createFolderPOToCreateFolderContext(po);
        Long fileId = userFileService.createFolder(context);
        return R.data(IdUtil.encrypt(fileId));//加密后返回
    }

    @PutMapping("file")
    @ApiOperation(value = "更新文件名称")
    public R updateFilename(@Validated @RequestBody UpdateFilenamePO po) {
        UpdateFilenameContext context = fileConverter.updateFilenamePOToUpdateFilenameContext(po);
        userFileService.updateFilename(context);
        return R.success();
    }

    @DeleteMapping("file")
    @ApiOperation(value = "批量删除文件")
    public R deleteFiles(@Validated @RequestBody DeleteFilePO po) {
        DeleteFileContext context = fileConverter.deleteFilePOToDeleteFileContext(po);
        String fileIds = po.getFileIds();
        //将String转为List<Long>
        List<Long> fileIdList = Splitter.on(BPanConstants.COMMON_SEPARATOR).splitToList(fileIds)
                .stream().map(IdUtil::decrypt).collect(Collectors.toList());
        context.setFileIdList(fileIdList);
        userFileService.deleteFiles(context);
        return R.success();
    }

    @PostMapping("file/sec-upload")
    @ApiOperation(value = "文件秒传")
    public R secUpload(@Validated @RequestBody SecUploadPO secUploadPO) {
        SecUploadContext context = fileConverter.secUploadPOToSecUploadContext(secUploadPO);
        boolean success = userFileService.secUpload(context);
        if (success) {
            return R.success();
        }
        return R.fail("文件秒传失败");
    }

    @PostMapping("file/upload")
    @ApiOperation(value = "单文件上传")
    public R upload(@Validated @RequestBody FileUploadPO fileUploadPO) {
        FileUploadContext context = fileConverter.fileUploadPOToFileUploadContext(fileUploadPO);
        userFileService.upload(context);
        return R.success();
    }

    /*@PostMapping("file/chunk-upload")
    @ApiOperation(value = "文件分片上传",
            consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public R<FileChunkUploadVO> chunkUpload(@Validated FileChunkUploadPO po) {
        FileChunkUploadContext context = fileConverter.fileChunkUploadPOToFileChunkUploadContext(po);
        FileChunkUploadVO vo = userFileService.chunkUpload(context);
        return R.data(vo);
    }*/
    @ApiOperation(
            value = "文件分片上传",
            notes = "该接口提供了文件分片上传的功能",
            consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE
    )
    @PostMapping("file/chunk-upload")
    public R<FileChunkUploadVO> chunkUpload(@Validated FileChunkUploadPO fileChunkUploadPO) {
        FileChunkUploadContext context = fileConverter.fileChunkUploadPOToFileChunkUploadContext(fileChunkUploadPO);
        FileChunkUploadVO vo = userFileService.chunkUpload(context);
        return R.data(vo);
    }

    @GetMapping("file/chunk-upload")
    @ApiOperation(value = "查询用户已上传的文件分片列表")
    public R<UploadedChunksVO> getUploadedChunks(@Validated QueryUploadedChunksPO po) {
        QueryUploadedChunksContext context = fileConverter.queryUploadedChunksPOToQueryUploadedChunksContext(po);
        UploadedChunksVO vo = userFileService.getUploadedChunks(context);
        return R.data(vo);
    }

    @PostMapping("file/merge")
    @ApiOperation(value = "文件分片合并")
    public R mergeFile(@Validated @RequestBody FileChunkMergePO po) {
        FileChunkMergeContext context = fileConverter.fileChunkMergePOToFileChunkMergeContext(po);
        userFileService.mergeFile(context);
        return R.success();
    }

    @GetMapping("file/download")
    @ApiOperation(value = "下载文件")
    public void download(@NotBlank(message = "文件id不能为空") @RequestParam(value = "fileId", required = false) String fileId,
                         HttpServletResponse response) {
        FileDownloadContext context = new FileDownloadContext();
        context.setFileId(IdUtil.decrypt(fileId));
        context.setUserId(UserIdUtil.get());
        context.setResponse(response);
        userFileService.download(context);
    }

    @GetMapping("file/preview")
    @ApiOperation(value = "文件预览")
    public void preview(@NotBlank(message = "文件id不能为空") @RequestParam(value = "fileId", required = false) String fileId,
                        HttpServletResponse response) {
        FilePreviewContext context = new FilePreviewContext();
        context.setFileId(IdUtil.decrypt(fileId));
        context.setUserId(UserIdUtil.get());
        context.setResponse(response);
        userFileService.preview(context);
    }

    @ApiOperation(value = "查询文件树")
    @GetMapping("file/folder/tree")
    public R<List<FolderTreeNodeVO>> getFolderTree() {
        FolderTreeNodeContext context = new FolderTreeNodeContext();
        context.setUserId(UserIdUtil.get());
        List<FolderTreeNodeVO> folderTrees = userFileService.getFolderTree(context);
        return R.data(folderTrees);
    }

    @ApiOperation(value = "文件转移")
    @PostMapping("file/transfer")
    public R transfer(@Validated @RequestBody TransferFilePO po) {
        TransferFileContext context = new TransferFileContext();
        //解密fileIds
        List<Long> fileIdsList = Splitter.on(BPanConstants.COMMON_SEPARATOR).splitToList(po.getFileIds())
                .stream().map(IdUtil::decrypt).collect(Collectors.toList());
        context.setFileIdList(fileIdsList);
        context.setTargetParentId(IdUtil.decrypt(po.getTargetParentId()));
        context.setUserId(UserIdUtil.get());
        userFileService.transfer(context);
        return R.success();
    }

    @ApiOperation(value = "文件复制")
    @PostMapping("file/copy")
    public R copy(@Validated @RequestBody CopyFilePO po) {
        CopyFileContext context = new CopyFileContext();
        context.setFileIdList(Splitter.on(BPanConstants.COMMON_SEPARATOR).splitToList(po.getFileIds())
                .stream()
                .map(IdUtil::decrypt)
                .collect(Collectors.toList()));
        context.setTargetParentId(IdUtil.decrypt(po.getTargetParentId()));
        context.setUserId(UserIdUtil.get());
        userFileService.copy(context);
        return R.success();
    }

    @ApiOperation(value = "文件搜索")
    @GetMapping("file/search")
    public R<List<FileSearchResultVO>> search(@Validated FileSearchPO po) {
        FileSearchContext context = new FileSearchContext();
        context.setKeyword(po.getKeyword());
        if (StringUtils.isNotBlank(po.getFileTypes())) {
            List<Integer> fileTypeArray = Splitter.on(BPanConstants.COMMON_SEPARATOR).splitToList(po.getFileTypes())
                    .stream()
                    .map(Integer::valueOf)
                    .collect(Collectors.toList());
            context.setFileTypeArray(fileTypeArray);
        }
        context.setUserId(UserIdUtil.get());
        List<FileSearchResultVO> result = userFileService.search(context);
        return R.data(result);
    }

    @ApiOperation(value = "查询面包屑列表")
    @GetMapping("file/breadcrumbs")
    public R<List<BreadcrumbVO>> getBreadcrumbs(@NotBlank(message = "文件id不能为空")
                                                @RequestParam(value = "fileId", required = false) String fileId) {
        BreadcrumbContext context = new BreadcrumbContext();
        context.setFileId(IdUtil.decrypt(fileId));
        context.setUserId(UserIdUtil.get());
        List<BreadcrumbVO> result = userFileService.getBreadcrumbs(context);
        return R.data(result);
    }

}
